iT邦幫忙

2026 iThome 鐵人賽

DAY 22
0
佛心分享-IT 人自學之術

學過一點 React,卻被撈進 C#:新手用 AI 硬啃 MVC 企業專案的 3 個月實錄系列 第 22

Day 22|用 F12 從 Controller 追到 Service,資料怎麼一路查到資料庫?

  • 分享至 

  • xImage
  •  

上一篇整理完 Controller 和 Service 的分工後,我開始比較能看懂這種程式:

public IActionResult Detail(int id)
{
    var model = _userService.GetDetail(id);

    return View(model);
}

以前看到這段,我會有一個很直接的疑問:

就這樣?

資料到底在哪裡查?
SQL 寫在哪?
GetDetail() 裡面又在幹嘛?

因為 Controller 裡只看到:

_userService.GetDetail(id);

真正的處理邏輯根本不在這裡。

這時候我才開始真的用到 Visual Studio 很實用的一個功能:

F12

也就是:

Go To Definition
移至定義

這篇就來實際追一次:

Controller
↓
Service
↓
Repository / DBService / DbContext
↓
SQL
↓
Database

看看一筆資料到底是怎麼一路查出來的。

先從 Controller 開始

假設目前 Controller 是:

public class UserController : Controller
{
    private readonly IUserService _userService;

    public UserController(IUserService userService)
    {
        _userService = userService;
    }

    public IActionResult Detail(int id)
    {
        var model = _userService.GetDetail(id);

        return View(model);
    }
}

這時我最想知道的是:

GetDetail(id)

到底寫在哪裡。

我會把游標放在:

GetDetail

上面。

然後按:

F12

第一次 F12,可能先跳到 Interface

按下 F12 之後,不一定直接看到真正邏輯。

有時候會先跳到:

public interface IUserService
{
    UserDetailViewModel GetDetail(int id);
}

我第一次看到這裡會有點傻眼。

因為:

蛤?

怎麼只有一行?
真正程式呢?

這是因為:

IUserService

只是 Interface。

它主要在說:

這個 Service 應該提供 GetDetail() 這個功能

但不負責寫:

GetDetail() 到底怎麼做

可以先把它理解成:

IUserService
定義功能規格

UserService
真正實作功能

所以看到:

UserDetailViewModel GetDetail(int id);

沒有 { } 裡面的程式,不代表追錯了。

只是還沒追到底。

怎麼從 Interface 找到真正的 Service?

假設現在停在:

public interface IUserService
{
    UserDetailViewModel GetDetail(int id);
}

接著要找:

誰實作了 IUserService?

可以在:

IUserService

上使用:

F12

有時候可以透過 IDE 導航找到實作。

也可以使用:

尋找所有參考

或 Visual Studio 的:

Go To Implementation

來找實作類別。

最後可能找到:

public class UserService : IUserService
{
    public UserDetailViewModel GetDetail(int id)
    {
        ...
    }
}

這裡才是真正開始處理資料的地方。

Service 裡可能又會呼叫下一層

例如:

public class UserService : IUserService
{
    private readonly IUserRepository _userRepository;

    public UserService(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }

    public UserDetailViewModel GetDetail(int id)
    {
        var user = _userRepository.GetById(id);

        var model = new UserDetailViewModel
        {
            Name = user.Name,
            Email = user.Email
        };

        return model;
    }
}

這裡可以先拆成:

_userRepository.GetById(id)
↓
去取得資料

user
↓
拿到資料庫相關物件

UserDetailViewModel
↓
整理成畫面需要的資料

return model
↓
回給 Controller

所以 Service 裡不一定自己直接寫 SQL。

它可能又把資料存取交給:

Repository
DBService
DbContext

這時再按一次 F12

我看到:

_userRepository.GetById(id);

就可以繼續:

游標放在 GetById
↓
F12

可能又先跳到:

public interface IUserRepository
{
    User GetById(int id);
}

再找到真正實作:

public class UserRepository : IUserRepository
{
    public User GetById(int id)
    {
        ...
    }
}

這時整條追蹤線就變成:

UserController
↓
IUserService
↓
UserService
↓
IUserRepository
↓
UserRepository

第一次看到企業專案一直:

Ixxx
xxxService
IxxxRepository
xxxRepository

真的會覺得繞超遠。

但其實每一層都有自己的責任。

Repository 裡可能怎麼查資料?

如果專案使用 Entity Framework,可能看到:

public User GetById(int id)
{
    return _dbContext.Users
        .FirstOrDefault(x => x.Id == id);
}

這時就已經接近資料庫了。

可以拆成:

_dbContext.Users
↓
Users 這組資料

FirstOrDefault(...)
↓
找符合條件的第一筆

x.Id == id
↓
查詢條件

整條線就是:

Controller 傳入 id
↓
Service
↓
Repository
↓
DbContext
↓
Users
↓
依 id 查詢
↓
Database

也可能直接看到 SQL

不是每個企業專案都用 Entity Framework。

有些專案可能會看到:

public UserDto GetById(int id)
{
    string sql = @"
        SELECT Id, Name, Email
        FROM Users
        WHERE Id = @Id
    ";

    return _dbService.QueryFirstOrDefault<UserDto>(
        sql,
        new { Id = id }
    );
}

這時候就更直接。

可以看到:

SELECT
↓
查哪些欄位

FROM
↓
查哪張表

WHERE
↓
查詢條件

@Id
↓
傳入的參數

所以不同專案可能長得不一樣。

但追法其實一樣:

Controller
↓
Service
↓
下一個被呼叫的方法
↓
再 F12
↓
直到找到真正資料來源

還可能遇到 Stored Procedure

有些企業專案會把 SQL 寫在資料庫 Stored Procedure 裡。

程式可能只有:

return _dbService.Query<UserDto>(
    "usp_GetUserDetail",
    parameters
);

這時程式碼裡看不到完整 SQL。

那就要繼續確認:

usp_GetUserDetail

是不是資料庫裡的 Stored Procedure。

所以:

追到 DBService

不一定代表已經看到 SQL。

有時候真正查詢還藏在資料庫裡。

F12 最重要的不是快捷鍵,是「一直問下一層在哪」

我後來發現 F12 真正有用的地方,不是背快捷鍵。

而是建立一個習慣:

這個方法是誰呼叫的?

這個方法真正寫在哪?

裡面又呼叫了誰?

資料到底在哪一層拿到?

例如:

var model = _userService.GetDetail(id);

我會一路拆:

GetDetail()
↓
UserService.GetDetail()

裡面呼叫:
GetById()

↓
UserRepository.GetById()

裡面呼叫:
DbContext / SQL

↓
Database

這樣一個原本完全不知道資料從哪裡來的方法,就開始被拆開。

按 F12 之後怎麼回上一個地方?

這個超實用。

因為一直 F12 之後,很容易變成:

Controller
↓
Service
↓
Repository
↓
DbContext
↓
某個 Model
↓
另一個 Method

然後:

我剛剛到底從哪裡來的?

這時可以使用:

Ctrl + -

回到上一個瀏覽位置。

例如:

Controller
↓ F12
Service
↓ F12
Repository

想回 Service:

Ctrl + -

再按一次:

Ctrl + -

回 Controller。

這對追大型專案真的很好用。

Shift + F12 又是什麼?

F12 是:

這個東西定義在哪?

而:

Shift + F12

比較像:

哪些地方有使用這個東西?

例如我找到:

public UserDetailViewModel GetDetail(int id)

想知道:

這個方法還有哪些地方在用?

就可以找:

Find All References
尋找所有參考

這時可能看到:

UserController
AdminController
ReportService

都有呼叫它。

這個功能在準備修改共用方法前特別重要。

因為如果我只看到:

這個方法現在這一頁會用

就直接改。

結果它其實有五個地方都在用,就可能一起被影響。

所以我現在會記:

F12
往裡面追

Shift + F12
往外看誰在用

Alt + F12 呢?

Visual Studio 還有:

Alt + F12
Peek Definition

它可以在目前畫面直接開一個小視窗查看定義。

不用整個跳走。

例如我只是想快速確認:

UserDetailViewModel 裡有哪些欄位?

可以:

Alt + F12

看一下。

看完直接關掉。

如果只是短暫確認類別內容,會比一直跳檔案方便。

我目前會先把幾個功能記成:

F12
移至定義

Alt + F12
快速偷看定義

Shift + F12
找誰在使用

Ctrl + -
回上一個位置

不用一次背很多 Visual Studio 快捷鍵。

這四個已經很夠用。

資料到底怎麼一路回到 View?

前面一路往下追:

Controller
↓
Service
↓
Repository
↓
Database

但查完之後,資料還要一路回來。

例如 Repository:

public User GetById(int id)
{
    return _dbContext.Users
        .FirstOrDefault(x => x.Id == id);
}

回傳:

User Entity

Service 收到:

var user = _userRepository.GetById(id);

再整理:

var model = new UserDetailViewModel
{
    Name = user.Name,
    Email = user.Email
};

回 Controller:

var model = _userService.GetDetail(id);

最後:

return View(model);

View:

@model UserDetailViewModel

<h1>@Model.Name</h1>
<p>@Model.Email</p>

所以完整流程不是只有:

Controller
↓
Database

而是:

Request
↓
Controller
↓
Service
↓
Repository / DBService
↓
Database

資料查回來
↓

Entity / DTO
↓
Service
↓
ViewModel
↓
Controller
↓
View
↓
HTML

如果畫面資料錯了,我可以從哪裡開始追?

這就是 F12 真正開始有價值的地方。

假設畫面顯示:

部門名稱是空的

我可以先看 View:

@Model.DepartmentName

接著往回:

View
↓
UserDetailViewModel.DepartmentName
↓
Controller 的 return View(model)
↓
model 從哪裡來?
↓
_userService.GetDetail(id)
↓
F12

進 Service 後看:

DepartmentName = user.DepartmentName

再往下追:

user.DepartmentName 從哪裡來?
↓
Repository
↓
SQL / DbContext

最後就能判斷:

資料庫本來就沒有?

SQL 沒查 DepartmentName?

DTO 沒接到?

Service 轉 ViewModel 時漏掉?

Controller 傳錯 Model?

View 用錯欄位?

這比:

畫面空的
↓
直接在 View 亂改

有效很多。

不要看到 null 就直接怪資料庫

這也是我後來會特別注意的。

例如:

@Model.DepartmentName

顯示空白。

不代表:

Database 沒資料

資料有可能在 Repository 還正常:

DepartmentName = "資訊部"

但 Service 轉換時漏掉:

var model = new UserDetailViewModel
{
    Name = user.Name,
    Email = user.Email

    // 忘記 DepartmentName
};

最後 View 當然拿不到。

所以資料流裡任何一段都可能斷:

Database
↓
Repository
↓
Entity / DTO
↓
Service
↓
ViewModel
↓
Controller
↓
View

這也是為什麼後面要學中斷點。

F12 可以告訴我:

程式寫在哪裡

但它不能告訴我:

執行時資料現在到底是多少

我現在實際會怎麼追一個陌生方法?

假設 Controller 有:

var model = _userService.GetDetail(id);

我會照這個順序:

第一步
F12 GetDetail
↓
看看先到 Interface 還是實作

第二步
找到真正的 UserService.GetDetail()
↓
看它裡面又呼叫哪個方法

第三步
F12 Repository / DBService 方法
↓
找真正資料存取位置

第四步
確認查詢條件
↓
id 是不是一路傳下來?

第五步
確認查詢結果用什麼 Entity / DTO 接

第六步
回 Service
↓
看怎麼轉成 ViewModel

第七步
回 Controller
↓
確認 return View(model)

第八步
回 View
↓
確認 @Model 使用哪個欄位

如果途中跳太遠:

Ctrl + -

往回。

如果準備修改某個共用方法:

Shift + F12

先確認誰還在用。

這就是我現在追企業專案最常用的一條路。

AI 在這一篇幫了我什麼?

這次我主要問:

Controller 裡只看到 _userService.GetDetail(id),真正程式在哪裡?

F12 為什麼有時候只跳到 Interface?

Interface 和真正的 Service 實作要怎麼找到?

Service 裡又呼叫 Repository 時要繼續怎麼追?

Entity Framework、SQL、Stored Procedure 的專案,最後資料可能各自藏在哪裡?

AI 幫我先整理出:

Controller
↓
Interface
↓
Service
↓
Repository / DBService
↓
Database

但真正有幫助的是,我回到 Visual Studio 自己一路按 F12。

因為每個企業專案的分層都不一定一樣。

有些是:

Controller
↓
Service
↓
DbContext

有些是:

Controller
↓
Service
↓
Repository
↓
DbContext

也有可能:

Controller
↓
Service
↓
DBService
↓
SQL / Stored Procedure

AI 可以告訴我可能的方向。

但最後還是要以:

現在這個專案實際怎麼寫

為準。

這篇先記住什麼?

F12 最基本的用途是:

這個方法到底定義在哪裡?

但真正追企業專案時,我會把它當成:

沿著程式呼叫一路往下走

例如:

Controller
↓
Service Interface
↓
Service
↓
Repository / DBService
↓
DbContext / SQL
↓
Database

常用的幾個功能:

F12
移至定義

Alt + F12
快速查看定義

Shift + F12
尋找所有參考

Ctrl + -
回上一個位置

而查詢資料的完整方向可以先記成:

Controller
↓
Service
↓
資料存取層
↓
Database

↓

Entity / DTO
↓
Service 轉換
↓
ViewModel
↓
Controller
↓
View

所以現在看到:

_userService.GetDetail(id);

不會再覺得:

真正的程式是不是消失了?

而是知道:

游標放上去
↓
F12
↓
繼續追

不過 F12 只能告訴我:

程式碼寫在哪裡

還有一個更重要的問題:

執行的時候,
它真的有跑到這一行嗎?

下一篇就來用中斷點確認:

我找到程式碼了,但怎麼知道實際執行時真的有跑進這個方法?


上一篇
Day 21|Controller 為什麼不能什麼都自己做?Service 負責什麼?
系列文
學過一點 React,卻被撈進 C#:新手用 AI 硬啃 MVC 企業專案的 3 個月實錄22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言